package com.eastfair.config.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.boot.service.SuperCacheServiceImpl;
import com.eastfair.cache.configattribute.ConfigAttributeValueCacheKeyBuilder;
import com.eastfair.cache.repository.CacheOps;
import com.eastfair.config.contant.ConfigContant;
import com.eastfair.config.dao.ConfigAttributeValueMapper;
import com.eastfair.config.dto.ConfigAttributeValueDTO;
import com.eastfair.config.entity.ConfigAttributeValue;
import com.eastfair.config.service.ConfigAttributeValueService;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.model.CacheKeyBuilder;
import com.eastfair.core.utils.StringUtils;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.projectcore.dto.ConfigAttributeDTO;
import com.eastfair.projectcore.vo.ConfigAttributeVO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 *
 * </p>
 *
 * @author zjn
 * @date 2021-08-05
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class ConfigAttributeValueServiceImpl extends SuperCacheServiceImpl<ConfigAttributeValueMapper, ConfigAttributeValue> implements ConfigAttributeValueService {
    @Autowired
    private CacheOps cacheOps;
    @Autowired
    private ProjectCoreServiceFeign projectCoreServiceFeign;

    @Override
    protected CacheKeyBuilder cacheKeyBuilder() {
        return new ConfigAttributeValueCacheKeyBuilder();
    }

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(ConfigAttributeValue entity) {
        UpdateWrapper<ConfigAttributeValue> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(ConfigAttributeValue::getProjectId, ContextUtil.getProjectId()).eq(ConfigAttributeValue::getId, entity.getId());
        entity.setProjectId(null);
        //删除缓存
        delCache(entity);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(ConfigAttributeValue model) {
        //雪花ID
        model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        model.setProjectId(ContextUtil.getProjectId());
        return R.successDef();
    }

    @Override
    public void insertConfiguration(List<ConfigAttributeValueDTO> data) {
        Long flagId = DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId());
        List<ConfigAttributeValue> params = new ArrayList<>(data.size());
        data.forEach(e -> {
            e.setFlagId(flagId);
            e.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
            e.setProjectId(ContextUtil.getProjectId());
            ConfigAttributeValue param = new ConfigAttributeValue();
            BeanUtils.copyProperties(e, param);
            params.add(param);
        });

        saveBatch(params);
    }

    @Override
    public <T> List<T> listEntityByClass(Class<T> clazz) {
        List<Object> objects = listObjectByEntityClass(clazz.getName());
        if (objects != null && !objects.isEmpty()) {
            //转泛型
            return JSON.parseArray(JSON.toJSONString(objects), clazz);
        }
        return null;
    }

    @Override
    public <T> T getEntityByClass(Class<T> clazz) {
        List<T> list = listEntityByClass(clazz);
        if (list != null && !list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<Object> listObjectByEntityClass(String className) {
        ConfigAttributeDTO configAttributeDTO = new ConfigAttributeDTO();
        configAttributeDTO.setEntityClass(className);

        // 获取实体属性
        List<ConfigAttributeVO> configAttributeVOList = projectCoreServiceFeign.listByEntityClass(configAttributeDTO).getData();
        if(configAttributeVOList == null || configAttributeVOList.size() < 1) {
            return null;
        }
        List<Long> configAttributeIdList = configAttributeVOList.stream().map(ConfigAttributeVO::getId).collect(Collectors.toList());
        List<ConfigAttributeValue> configAttributeValues = listByAttributeIds(configAttributeIdList);

        if (configAttributeValues != null && !configAttributeValues.isEmpty()) {
            return convertToObjectList(configAttributeVOList, configAttributeValues);
        }
        return null;
    }

    /**
     * 根据属性查找对应的列
     *
     * @param configAttributeIdList 属性id集合
     * @return 属性类集合
     */
    public List<ConfigAttributeValue> listByAttributeIds(List<Long> configAttributeIdList) {
        QueryWrapper<ConfigAttributeValue> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ConfigAttributeValue::getProjectId, ContextUtil.getProjectId())
                .eq(ConfigAttributeValue::getIsDelete, BusinessConstant.DELETE_NO).eq(ConfigAttributeValue::getIsEnable, BusinessConstant.ENABLE_YES)
                .in(ConfigAttributeValue::getConfigAttributeId, configAttributeIdList)
                .orderByAsc(ConfigAttributeValue::getFlagId);
        return list(wrapper);
    }

    /**
     * 获取对象的Object集合
     *
     * @param configAttributeVOList 属性集合
     * @param configAttributeValues 属性值集合
     * @return 属性object类集合
     */
    public List<Object> convertToObjectList(List<ConfigAttributeVO> configAttributeVOList, List<ConfigAttributeValue> configAttributeValues) {
        //对实体属性进行分组
        Map<Long, List<ConfigAttributeVO>> configAttributeMap = configAttributeVOList.stream().collect(Collectors.groupingBy(ConfigAttributeVO::getId));

        // 对属性值集合进行分组
        Map<Long, List<ConfigAttributeValue>> map = configAttributeValues.stream().collect(Collectors.groupingBy(ConfigAttributeValue::getFlagId));
        List<Object> result = new ArrayList<>();

        try {
            //获取对象类型
            Class<?> entityClass = Class.forName(configAttributeVOList.get(0).getEntityClass());
            // 获取对象属性
            Field[] fields = entityClass.getDeclaredFields();
            for (Long key : map.keySet()) {
                Object obj = entityClass.newInstance();
                List<ConfigAttributeValue> entityValues = map.get(key);
                for (Field field : fields) {
                    if (ConfigContant.FLAG_ID.equals(field.getName())) {
                        // 设置标识id  flagId
                        String methodKey = StringUtils.capitalize(field.getName());
                        Method method = entityClass.getDeclaredMethod(ConfigContant.METHOD_SET + methodKey, field.getType());
                        method.invoke(obj, entityValues.get(0).getFlagId());
                    } else {
                        // 设置业务属性
                        for (ConfigAttributeValue configAttributeValue : entityValues) {
                            ConfigAttributeVO configAttributeVo = configAttributeMap.get(configAttributeValue.getConfigAttributeId()).get(0);
                            if (configAttributeVo.getAttributeCode().equals(field.getName())) {
                                String methodKey = StringUtils.capitalize(field.getName());
                                Method method = entityClass.getDeclaredMethod(ConfigContant.METHOD_SET + methodKey, field.getType());
                                //转换值为指定的类型并调用方法
                                Object value;
                                if(Objects.isNull(configAttributeValue.getConfigAttributeValue())) {
                                    value = null;
                                }else {
                                     value = StringUtils.convertToClass(configAttributeValue.getConfigAttributeValue(), field.getType());
                                }
                                method.invoke(obj, value);
                                break;
                            }
                        }

                    }
                }
                result.add(obj);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return result;
    }

    @Override
    public Boolean updateValue(Long flagId, Long configAttributeId, String value) {
        // 清缓存
        QueryWrapper<ConfigAttributeValue> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ConfigAttributeValue::getProjectId, ContextUtil.getProjectId()).eq(ConfigAttributeValue::getFlagId, flagId)
                .eq(ConfigAttributeValue::getConfigAttributeId, configAttributeId).eq(ConfigAttributeValue::getIsDelete, BusinessConstant.DELETE_NO);
        List<ConfigAttributeValue> configAttributeValueList = list(queryWrapper);
        if (configAttributeValueList != null && !configAttributeValueList.isEmpty()) {
            List<Long> ids = configAttributeValueList.stream().map(ConfigAttributeValue::getId).collect(Collectors.toList());
            delCache(ids);
        }

        // 修改
        UpdateWrapper<ConfigAttributeValue> wrapper = new UpdateWrapper<>();
        wrapper.lambda().set(ConfigAttributeValue::getConfigAttributeValue, value)
                .eq(ConfigAttributeValue::getProjectId, ContextUtil.getProjectId())
                .eq(ConfigAttributeValue::getFlagId, flagId)
                .eq(ConfigAttributeValue::getConfigAttributeId, configAttributeId);
        return update(wrapper);
    }

    @Override
    @GlobalTransactional(name = "saveEntity", rollbackFor = Exception.class)
    public <T> Boolean saveEntity(T t) {
        if (Objects.isNull(t)) {
            throw new NullPointerException("object is null");
        }
        // 获取对象class
        Class<?> clazz = t.getClass();
        Map<String, Long> configAttributeMap = convertAttributeCodeIdMap(clazz);

        // 获取对象属性
        Field[] fields = clazz.getDeclaredFields();
        List<ConfigAttributeValue> params = new ArrayList<>();
        List<Long> ids = DefaultUidGenerator.getBatUidOfProjectId(ContextUtil.getProjectId(), fields.length + 1);
        for (int i = 0; i < fields.length; i++) {
            ConfigAttributeValue configAttributeValue = new ConfigAttributeValue();
            configAttributeValue.setId(ids.get(i));
            configAttributeValue.setProjectId(ContextUtil.getProjectId());
            configAttributeValue.setFlagId(ids.get(ids.size() - 1));
            configAttributeValue.setConfigAttributeId(configAttributeMap.get(fields[i].getName()));
            if (ConfigContant.FLAG_ID.equals(fields[i].getName())) {
                continue;
            }

            try {
                String methodKey = StringUtils.capitalize(fields[i].getName());
                Method method = clazz.getDeclaredMethod(ConfigContant.METHOD_GET + methodKey);
                String value = Convert.convert(String.class, method.invoke(t));
                if (!StringUtils.isBlank(value)) {
                    configAttributeValue.setConfigAttributeValue(value);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                log.error(e.getMessage());
                return false;
            }
            params.add(configAttributeValue);
        }
        return saveBatch(params);
    }

    @Override
    @GlobalTransactional(name = "updateEntity", rollbackFor = Exception.class)
    public <T> Boolean updateEntity(T t) {
        if (Objects.isNull(t)) {
            throw new NullPointerException("object is null");
        }
        // 获取对象class
        Class<?> clazz = t.getClass();
        Map<String, Long> configAttributeMap = convertAttributeCodeIdMap(clazz);

        // 获取对象的标识id
        Long flagId;
        try {
            Method method = clazz.getDeclaredMethod(ConfigContant.METHOD_GET + StringUtils.capitalize(ConfigContant.FLAG_ID));
            flagId = Convert.convert(Long.class, method.invoke(t));
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            log.error(e.getMessage());
            return false;
        }
        if (Objects.isNull(flagId)) {
            log.error("flagId is undefined");
            return false;
        }

        // 获取对象属性
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (ConfigContant.FLAG_ID.equals(field.getName())) {
                continue;
            }

            String methodKey = StringUtils.capitalize(field.getName());
            try {
                Method method = clazz.getDeclaredMethod(ConfigContant.METHOD_GET + methodKey);
                String value = Convert.convert(String.class, method.invoke(t));
                if (StringUtils.isBlank(value)) {
                    continue;
                }

                // 清缓存
                QueryWrapper<ConfigAttributeValue> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(ConfigAttributeValue::getProjectId, ContextUtil.getProjectId())
                        .eq(ConfigAttributeValue::getFlagId, flagId).eq(ConfigAttributeValue::getConfigAttributeId, configAttributeMap.get(field.getName()))
                        .eq(ConfigAttributeValue::getIsEnable, BusinessConstant.ENABLE_YES).eq(ConfigAttributeValue::getIsDelete, BusinessConstant.DELETE_NO);
                ConfigAttributeValue configAttributeValue = getOne(queryWrapper, false);
                if (!Objects.isNull(configAttributeValue)) {
                    delCache(configAttributeValue.getId());
                }

                UpdateWrapper<ConfigAttributeValue> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().eq(ConfigAttributeValue::getProjectId, ContextUtil.getProjectId()).eq(ConfigAttributeValue::getFlagId, flagId)
                        .eq(ConfigAttributeValue::getConfigAttributeId, configAttributeMap.get(field.getName()))
                        .set(ConfigAttributeValue::getConfigAttributeValue, value);
                update(updateWrapper);

            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                log.error(e.getMessage());
                return false;
            }
        }
        return true;
    }

    /**
     * 获取去class对象所有属性的attributeCode, id映射关系
     *
     * @param clazz 实体class
     * @return attributeCode, id映射关系
     */
    private Map<String, Long> convertAttributeCodeIdMap(Class clazz) {
        // 获取该类下所有的属性信息
        ConfigAttributeDTO configAttributeDTO = new ConfigAttributeDTO();
        configAttributeDTO.setEntityClass(clazz.getName());
        List<ConfigAttributeVO> configAttributeVOList = projectCoreServiceFeign.listByEntityClass(configAttributeDTO).getData();
        // 转换为Map<attributeCode, id>
        return configAttributeVOList.stream().collect(Collectors.toMap(ConfigAttributeVO::getAttributeCode, ConfigAttributeVO::getId));

    }
}
